/****************************************************
	文件：ResCtrl.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2021/1/2 21:59:25
	功能：资源加载控制器
*****************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;
using HTFW.Core;
using HTFW.Logger;
using HTFW.Utility.Global;
using IDisposable = HTFW.Core.IDisposable;
using Object = UnityEngine.Object;

namespace HTFW.Res
{
    public class ResService : Singleton<ResService>, IService
    {
        List<IDisposable> mResSubModuleLst; //资源加载子模块列表

        ResClassObjectPool mClassPool; //资源加载类对象池
        ResCache mCache; //资源缓存
        ResScheduler mScheduler; //资源加载调度器
        ResConfig mCfg; //资源配置管理

        /// <summary>
        /// 是否为模拟模式下的资源加载
        /// </summary>
        public static bool IsSimulationMode { get; private set; }

        public void Init(params object[] args)
        {
            IsSimulationMode = PlayerPrefs.GetInt(ResDefine.RES_LOAD_MODE_KEY) == 1;
            HLog.Info(IsSimulationMode ? "使用模拟模式进行资源加载" : "使用AssetBundle模式进行资源加载");

            mResSubModuleLst = new List<IDisposable>();

            mClassPool = ResClassObjectPool.Instance;
            mClassPool.Init();
            RegisterModule(mClassPool);

            mCache = ResCache.Instance;
            mCache.Init();
            RegisterModule(mCache);

            mScheduler = ResScheduler.Instance;
            mScheduler.Init();
            RegisterModule(mScheduler);

            mCfg = ResConfig.Instance;
            mCfg.Init();
            RegisterModule(mCfg);
        }

        public void Dispose()
        {
            foreach (var item in mResSubModuleLst)
                item.Dispose();

            mResSubModuleLst = null;
            
            Resources.UnloadUnusedAssets();
        }

        /// <summary>
        /// 注册模块
        /// </summary>
        void RegisterModule(IDisposable module)
        {
            mResSubModuleLst.Add(module);
        }

        /// <summary>
        /// 同步加载
        /// </summary>
        /// <param name="path">资源全路径（带后缀）</param>
        /// <returns></returns>
        public ResData LoadSync(string path, bool isSprite = false)
        {
            if (ResCache.Instance.TryGet(path, out ResData res))
            {
                res.LoadStartTime = DateTime.Now.Ticks;

                res.IncreaseRef();

                res.LoadEndTime = DateTime.Now.Ticks;
                HLog.Debug($"LoadSync done.  {res.LoadTime}");

                return res;
            }

            if (ResConfig.Instance.TryGet(path, out ResData assetRes))
            {
                assetRes.LoadStartTime = DateTime.Now.Ticks;
                assetRes.IsSprite = isSprite;

                IResLoader assetLoader = ResClassObjectPool.Instance.SpawnAssetLoader();
                assetLoader.LoadSync(assetRes);

                assetRes.LoadEndTime = DateTime.Now.Ticks;
                HLog.Debug($"LoadSync done.  {assetRes.LoadTime}");

                return assetRes;
            }

            HLog.Error($"LoadSync error, 配置中不存在资源：{path}");
            return null;
        }

        /// <summary>
        /// 异步加载
        /// </summary>
        /// <param name="path">资源全路径（带后缀）</param>
        /// <param name="priority">异步加载优先级</param>
        /// <param name="onCompleted">加载完成时回调</param>
        /// <returns></returns>
        public ILoadResult LoadAsync(string path, ResTaskPriority priority, Action<ResData> onCompleted,
            bool isSprite = false)
        {
            if (ResCache.Instance.TryGet(path, out ResData res))
            {
                res.LoadStartTime = DateTime.Now.Ticks;

                res.IncreaseRef();

                res.LoadEndTime = DateTime.Now.Ticks;
                HLog.Debug($"LoadAsync done.  {res.LoadTime}");

                onCompleted?.Invoke(res);
                return res.AsyncResult;
            }

            if (ResConfig.Instance.TryGet(path, out ResData assetRes))
            {
                assetRes.Priority = priority;
                assetRes.LoadStartTime = DateTime.Now.Ticks;
                assetRes.IsSprite = isSprite;

                IResLoader assetLoader = ResClassObjectPool.Instance.SpawnAssetLoader();
                return assetLoader.LoadAsync(assetRes, () =>
                {
                    assetRes.LoadEndTime = DateTime.Now.Ticks;
                    HLog.Debug($"LoadAsync done.  {assetRes.LoadTime}");

                    onCompleted?.Invoke(assetRes);
                });
            }

            HLog.Error($"LoadAsync error, 配置中不存在资源：{path}");
            return null;
        }

        /// <summary>
        /// 资源卸载
        /// </summary>
        /// <param name="path"></param>
        public void Unload(string path)
        {
            if (!ResCache.Instance.TryGet(path, out ResData assetRes))
            {
                HLog.Error($"Unload error! 尚未加载资源：{path}");
            }
            else
            {
                if (assetRes.ResType != ResType.Asset)
                {
                    HLog.Warning("非 Asset 资源不可手动卸载");
                    return;
                }

                //卸载 自身 Asset
                assetRes.DecreaseRef();
            }
        }
        
        /// <summary>
        /// 资源卸载
        /// </summary>
        /// <param name="assetRes"></param>
        public void Unload(ResData assetRes)
        {
            if (!ResCache.Instance.Contains(assetRes))
            {
                HLog.Error($"Unload error! 尚未加载资源：{assetRes.Path}");
            }
            else
            {
                if (assetRes.ResType != ResType.Asset)
                {
                    HLog.Warning("非 Asset 资源不可手动卸载");
                    return;
                }

                //卸载 自身 Asset
                assetRes.DecreaseRef();
            }
        }
    }
}